#pragma once
#include <vector>
#include <memory>
#include <string>
#include <map>
#include <set>
#include "zen_log.h"
#include "zen_matrix.h"
#include "zen_point.h"
#include "zen_color.h"

#define ZEN_VAP_DEBUG 1
#if ZEN_VAP_DEBUG || 1
#define VAP_LOGD(...) Zen::LogD(__VA_ARGS__)
#else
#define VAP_LOGD(...)
#endif

#define VAP_OBJECT_DEBUG 1

namespace Zen
{
	namespace Game
	{

		class Object : public std::enable_shared_from_this<Object>
		{
		public:
			template <typename TSubObject>
			std::shared_ptr<TSubObject> GetSharedFromThis()
			{
				return std::dynamic_pointer_cast<TSubObject>(this->shared_from_this());
			}

		public:
			Object()
			{
				mObjectId = sTotalObjectCount++;

				VAP_LOGD("new GameObject [%s] ID:%lld Total:%d", mObjectName.c_str(), mObjectId, sTotalObjectCount);
#if VAP_OBJECT_DEBUG
				sAll.insert(this);
#endif
			}
			virtual ~Object()
			{
				--sTotalObjectCount;

				VAP_LOGD("delete GameObject [%s] ID:%lld Total:%d", mObjectName.c_str(), mObjectId, sTotalObjectCount);

#if VAP_OBJECT_DEBUG
				sAll.erase(this);
#endif
			}

			void SetObjectName(std::string const& name)
			{
				mObjectName = name;
			}

			auto const& GetObjectName()
			{
				return mObjectName;
			}

			int GetObjectID()
			{
				return mObjectId;
			}

		protected:
			std::string mObjectName;
			int mObjectId;
			static int sTotalObjectCount;
			Object(Object&) = delete;

		public:
#if VAP_OBJECT_DEBUG
			static std::set<Object*> sAll;
#endif
		};

		inline Point2 ToPoint2(P2i const& p)
		{
			return Point2Make(float(p.x), float(p.y));
		}

		inline Point4 ToPoint4(Color4f const& c)
		{
			return Point4Make(c.red, c.green, c.blue, c.alpha);
		}

		struct Area
		{
			float x = 0;
			float y = 0;
			float w = 0;
			float h = 0;
		};

		class RenderStack
		{
		public:
			// matrix is just a reference
			void PushMatrix(Mat4 const* matrix, int version);
			void PopMatrix();
			Mat4 const* GetTopMatrix();
			int GetTopMatrixVersion();

			void Reset();

		protected:
			std::vector<std::pair<Mat4 const*, int>> mMatrixStack{};
		};

	} // namespace Game
} // namespace Zen
